package controler.algorithms;

import java.util.LinkedList;

/** 
 * @file NNBP_Extraction.java  
 * 
 **/

/**
 *    Implementacja interfejsu ekstrakcji uzywana przez siec neuronowa z propagacja wsteczna.
 *  Klasa implementujaca ekstrakcje cech dla algorytmu sieci neuronowej z propagacja wsteczna.
 *  Klasa zajmuje sie odpowiednim przygotowaniem cech dla sieci neuronowej z propagacja wsteczna.
 */

public class NNBP_Extraction extends Extraction {
	
	private int historyDepth = 1;
	
	/**
     *   Konstruktor tworzacy ekstrakcje dla sieci neuronowej z propagacja wsteczna.
     * @param historyDepth ilosc pomiarow poprzedzajacych moment, ktory chcemy przewidziec, ktore sa brane pod uwage przy predykcji.
     */
	public NNBP_Extraction(int historyDepth)
	{
		this.historyDepth = historyDepth;
	}
	
	/**
     *   Metoda przygotowujaca cechy dla sieci neuronowej.
     * Metoda przygotowuje liste zawierajaca kolejne tablice cech, przygotowanych odpowiednio dla sieci neuronowej z propagacja wsteczna na podstawie podanego zbioru pomiarow.
     * @param dataSet lista bedaca oryginalnym zbiorem, ktory jest odpowiednio przeksztalcany na cechy dla sieci.
     * @return Lista zawietajaca kolejne tablice cech, przygotowane odpowiednio dla sieci neuronowej.
     */
	public LinkedList<double[]> extract(LinkedList<double[]> dataSet)
	{
		LinkedList<double[]> set = new LinkedList<double[]>();
		
		for (int i = historyDepth - 1 ; i < dataSet.size() ; i++)
		{
			double[] values = dataSet.get(i);
			
			double[] features = new double[17 + historyDepth - 1];
			
			double differencesSum = 0;
			int intensitySum = 0;
			double variance = 0;
			
			features[0] = values[5];		//oryginalna ilosc samochodow
			
			if (values[2] == 1)
				features[1] = 1;			//poniedzialek
			else if (values[2] == 2)
				features[2] = 1;			//wtorek
			else if (values[2] == 3)
				features[3] = 1;			//sroda
			else if (values[2] == 4)
				features[4] = 1;			//czwartek
			else if (values[2] == 5)
				features[5] = 1;			//piatek
			else if (values[2] == 6)
				features[6] = 1;			//sobota
			else if (values[2] == 0)
				features[7] = 1;			//niedziela
			
			features[8] = (1/1440.0) * values[4];			//czas w minutach
			features[9] = (1/11.0) * values[3];				//miesiac
			features[10] = (1/70.0) * (values[7] + 20);		//temparatura powietrza
			features[11] = (1/70.0) * (values[8] + 20);		//temparatura odczuwalna
			features[12] = 0.01 * values[14];				//intensywnosc opadu
			features[13] = (1/40.0) * values[16];			//predkosc wiatru
			features[14] = (1/120.0) * values[6];			//srednia predkosc samochodow
			
			for (int j = 16 + historyDepth - 1 ; j >= 17 ; j--)
			{
				features[j] = 0.5 + (1/130.0) * (dataSet.get(i - (j + 1 - 17))[5] - dataSet.get(i - (j + 1 - 17 - 1))[5]);	//kolejne roznice w natezeniu miedzy pomiarami
				differencesSum += features[j];
			}
			
			for (int j = 0 ; j < historyDepth ; j++)
			{
				intensitySum += dataSet.get(i - j)[5];
			}
			features[15] = (1/400.0) * (intensitySum / historyDepth);	//srednie natezenie z branych pod uwage pomiarow
			
			for(int j=0; j < historyDepth; j++)
			{
				variance += Math.pow(features[15] - dataSet.get(i - j)[5],2);	
			}
			features[16] = (1/10000.0) * (variance / historyDepth);		//wariancja natezenia z branych pod uwage pomiarow
			
			set.add(features);
		}
		
		return set;
	}

}
